package com.zp.base.impl.scheduling;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zp.base.api.vo.PriceListVo;
import com.zp.base.entity.scheduling.ClinicForRegist;
import com.zp.base.entity.scheduling.ClinicIndex;
import com.zp.base.entity.scheduling.ClinicSchedule;
import com.zp.base.entity.scheduling.bo.ClinicForRegistBo;
import com.zp.base.entity.scheduling.vo.ClinicForRegistVo;
import com.zp.base.entity.scheduling.vo.ClinicIndexVo;
import com.zp.base.mapper.scheduling.ClinicForRegistMapper;
import com.zp.base.mapper.scheduling.ClinicIndexMapper;
import com.zp.base.mapper.scheduling.ClinicScheduleMapper;
import com.zp.base.service.clinicItemDict.IClinicItemDictService;
import com.zp.base.service.scheduling.IClinicForRegistService;
import com.zp.common.core.constant.CacheNames;
import com.zp.common.core.utils.DateUtils;
import com.zp.common.core.utils.StringUtils;
import com.zp.common.myBatis.core.page.PageQuery;
import com.zp.common.myBatis.core.page.TableDataInfo;
import com.zp.common.redis.utils.CacheUtils;
import com.zp.system.api.entity.SysDept;
import com.zp.system.api.entity.SysUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 号表安排Service业务层处理
 *
 * @author zhang peng
 * @ date 2023-01-20
 */
@RequiredArgsConstructor
@Service
public class ClinicForRegistServiceImpl implements IClinicForRegistService {

    private final ClinicForRegistMapper baseMapper;
    private final ClinicIndexMapper clinicIndexMapper;
    private final ClinicScheduleMapper clinicScheduleMapper;
    private final IClinicItemDictService clinicItemDictService;

    /**
     * 用户信息
     */
    static Map<String, SysUser> sysUserMap = CacheUtils.get(CacheNames.SYS_USER);

    static Map<String, SysDept> sysDeptMap = CacheUtils.get(CacheNames.SYS_DEPT);

    /**
     * 查询号表安排
     */
    @Override
    public ClinicForRegistVo queryById(String clinicForRegistId) {
        return baseMapper.selectVoById(clinicForRegistId);
    }

    /**
     * 查询号表安排列表(分页)
     */
    @Override
    public TableDataInfo<ClinicForRegistVo> queryPageList(ClinicForRegistBo bo) {
        List<String> clinicScheduleList = new ArrayList<>();
        clinicScheduleList.add("");
        List<ClinicIndex> indexList = clinicIndexMapper.selectList(Wrappers.<ClinicIndex>lambdaQuery()
                .eq(ClinicIndex::getOrgId, bo.getOrgId()));
        LambdaQueryWrapper<ClinicForRegist> lqw = buildQueryWrapper(bo);
        if (CollectionUtil.isNotEmpty(bo.getClinicScheduleList())) {
            clinicScheduleList = bo.getClinicScheduleList().stream().map(ClinicSchedule::getScheduleId).distinct().collect(Collectors.toList());
        }
        lqw.in(ClinicForRegist::getClinicScheduleId, clinicScheduleList);
        lqw.orderByAsc(ClinicForRegist::getClinicIndexId, ClinicForRegist::getClinicDate);
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageNum(bo.getPageNum());
        pageQuery.setPageSize(bo.getPageSize());
        Page<ClinicForRegistVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        if (CollectionUtil.isNotEmpty(indexList)) {
            result.getRecords().forEach(item -> {
                item.setClinicIndexName(indexList.stream().filter(i -> StringUtils.equals(i.getClinicIndexId(), item.getClinicIndexId())).findAny().get().getName());
            });
        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询号表安排列表(不分页)
     */
    @Override
    public List<ClinicForRegistVo> queryList(ClinicForRegistBo bo) {
        if (StringUtils.isNotBlank(bo.getClinicDateStr())) {
            bo.setClinicDate(DateUtils.parseDate(bo.getClinicDateStr()));
        }
        // 获取号源信息list
        List<ClinicIndexVo> clinicIndexVoList = clinicIndexMapper.selectVoList(Wrappers.<ClinicIndex>lambdaQuery()
                .eq(ClinicIndex::getOrgId, bo.getOrgId()));
        // 匹配价表信息
        List<String> itemClassArray = new ArrayList<>();
        itemClassArray.add("E");
        itemClassArray.add("I");
        itemClassArray.add("P");
        itemClassArray.add("J");
        itemClassArray.add("K");
        itemClassArray.add("L");
        itemClassArray.add("Z");
        List<PriceListVo> priceLists = clinicItemDictService.getPriceList(bo.getOrgId(), itemClassArray, new ArrayList<>());
        LambdaQueryWrapper<ClinicForRegist> lqw = buildQueryWrapper(bo);
        // 获取号表明细list
        List<ClinicForRegistVo> list = baseMapper.selectVoList(lqw);
        list.forEach(item -> {
            ClinicIndexVo clinicIndexVo = new ClinicIndexVo();
            if (CollectionUtils.isNotEmpty(clinicIndexVoList)) {
                // 匹配号表和号源相同的信息
                clinicIndexVo = clinicIndexVoList.stream()
                        .filter(clinicIndex -> StringUtils.equals(item.getClinicIndexId(), clinicIndex.getClinicIndexId()))
                        .findAny().get();
            }
            SysDept sysDept = ObjectUtil.isNotNull(sysDeptMap.get(clinicIndexVo.getDeptId())) ? sysDeptMap.get(clinicIndexVo.getDeptId()) : new SysDept();
            clinicIndexVo.setDeptName(StringUtils.isNotBlank(clinicIndexVo.getDeptId()) ? sysDept.getDeptName() : "");
            clinicIndexVo.setDeptSort(sysDept.getOrderNum());
            clinicIndexVo.setDoctorName(StringUtils.isNotBlank(clinicIndexVo.getDoctorId()) && ObjectUtil.isNotNull(sysUserMap.get(clinicIndexVo.getDoctorId())) ? sysUserMap.get(clinicIndexVo.getDoctorId()).getNickName() : "");
            item.setClinicIndexVo(clinicIndexVo);
            // 匹配价表信息
            if (CollectionUtils.isNotEmpty(priceLists)) {
                List<PriceListVo> retPriceList = priceLists.stream()
                        .filter(priceList -> StringUtils.equals(priceList.getClinicItemId(), item.getClinicIndexVo().getClinicItemId())).collect(Collectors.toList());
                item.setPriceListVoList(retPriceList);
                item.setTotalPrice(retPriceList.stream()
                        .map(PriceListVo::getPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add));
            }
        });
        if (StringUtils.isNotBlank(bo.getDeptIdParam())) {
            list = list.stream().filter(item ->
                            StringUtils.isNotBlank(bo.getDeptIdParam()) && StringUtils.equals(item.getClinicIndexVo().getDeptId(), bo.getDeptIdParam())
                                    || StringUtils.isBlank(bo.getDeptIdParam()))
                    .collect(Collectors.toList());
        }
        if (StringUtils.isNotBlank(bo.getDoctorParam())) {
            list = list.stream().filter(item ->
                            StringUtils.isNotBlank(bo.getDoctorParam()) && StringUtils.equals(item.getClinicIndexVo().getDoctorId(), bo.getDoctorParam())
                                    || StringUtils.isBlank(bo.getDoctorParam()))
                    .collect(Collectors.toList());
        }
        list = list.stream().sorted((item, i2) -> item.getClinicIndexVo().getDeptSort()).collect(Collectors.toList());
        return list;
    }

    private LambdaQueryWrapper<ClinicForRegist> buildQueryWrapper(ClinicForRegistBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ClinicForRegist> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getClinicIndexId()), ClinicForRegist::getClinicIndexId, bo.getClinicIndexId());
        lqw.eq(bo.getClinicDate() != null, ClinicForRegist::getClinicDate, bo.getClinicDate());
        lqw.eq(StringUtils.isNotBlank(bo.getTimeDesc()), ClinicForRegist::getTimeDesc, bo.getTimeDesc());
        lqw.eq(bo.getLimitNum() != null, ClinicForRegist::getLimitNum, bo.getLimitNum());
        lqw.eq(bo.getLimitPreNum() != null, ClinicForRegist::getLimitPreNum, bo.getLimitPreNum());
        lqw.eq(bo.getCurrentNum() != null, ClinicForRegist::getCurrentNum, bo.getCurrentNum());
        lqw.eq(bo.getCurrentRegisNum() != null, ClinicForRegist::getCurrentRegisNum, bo.getCurrentRegisNum());
        lqw.eq(bo.getCurrentPreNum() != null, ClinicForRegist::getCurrentPreNum, bo.getCurrentPreNum());
        lqw.eq(StringUtils.isNotBlank(bo.getOrgId()), ClinicForRegist::getOrgId, bo.getOrgId());
        return lqw;
    }

    /**
     * 新增号表安排
     */
    @Override
    public Boolean insertByBo(ClinicForRegistBo bo) {
        boolean flag = false;
        List<ClinicForRegist> clinicForRegistList = new ArrayList<>();
        // 查询当前机构所有排班信息
        List<ClinicForRegist> clinicForRegistListOld = baseMapper.selectList(
                Wrappers.<ClinicForRegist>lambdaQuery()
                        .eq(ClinicForRegist::getOrgId, bo.getOrgId())
        );
        //获取前台传入的时间段开始和结束日期之间的所有日期
        Map<String, JSONObject> dateMap = DateUtils.getDayListBetweenFromAndToDay(bo.getStartDate(), bo.getStopDate());
        if (CollectionUtil.isNotEmpty(dateMap)) {
            dateMap.forEach((key, value) -> {
//                System.out.println(key + "-------" + value);
                // 获取日期
                String start = value.getString("start");
                // 获取当前日期的星期
                String weeKCode = value.getString("weekCode");
                bo.getClinicScheduleList().forEach(clinicSchedule -> {
                    // 判断前台传入的号别日期的星期 和 右侧现在的时间段星期是否对应的上，能对应上进行号表数据保存
                    if (StringUtils.equals(weeKCode, clinicSchedule.getDayOfWeek())) {
                        // 判断前台传入的排班信息数据库是否已存在（出诊安排id && 出诊日期）
                        boolean type = clinicForRegistListOld.stream().anyMatch(m ->
                                m.getClinicScheduleId().equals(clinicSchedule.getScheduleId())
                                        && DateUtils.dateTime(m.getClinicDate()).equals(DateUtils.dateTime(DateUtils.parseDate(start)))
                        );
                        if (!type) {
                            ClinicForRegist clinicForRegist = new ClinicForRegist();
                            clinicForRegist.setClinicScheduleId(clinicSchedule.getScheduleId());
                            clinicForRegist.setClinicIndexId(clinicSchedule.getClinicIndexId());
                            clinicForRegist.setClinicDate(DateUtils.parseDate(start));
                            clinicForRegist.setTimeDesc(clinicSchedule.getTimeDesc());
                            clinicForRegist.setLimitNum(ObjectUtil.isNull(clinicSchedule.getLimitNum()) ? 0L : clinicSchedule.getLimitNum());
                            clinicForRegist.setLimitPreNum(ObjectUtil.isNull(clinicSchedule.getLimitPreNum()) ? 0L : clinicSchedule.getLimitPreNum());
                            clinicForRegist.setCurrentNum(0L);
                            clinicForRegist.setCurrentPreNum(0L);
                            clinicForRegist.setCurrentRegisNum(0L);
                            clinicForRegist.setOrgId(bo.getOrgId());
                            clinicForRegist.setDelFlag("0");
                            clinicForRegistList.add(clinicForRegist);
                        }
                    }
                });
            });
            if (CollectionUtil.isEmpty(clinicForRegistList)) {
                throw new RuntimeException("没有符合的排班信息信息");
            }
//            List<ClinicForRegist> clinicForRegistListNew = clinicForRegistList.stream().filter(
//                    item -> clinicForRegistListOld.stream().allMatch(d -> item.getClinicScheduleId().equals(d.getClinicScheduleId())
//                    )).collect(Collectors.toList());
            flag = baseMapper.insertBatch(clinicForRegistList);
        }
        return flag;
    }

    /**
     * 修改号表安排
     */
    @Override
    public Boolean updateByBo(ClinicForRegistBo bo) {
        ClinicForRegist update = baseMapper.selectById(bo.getClinicForRegistId());
        if (ObjectUtil.isNotNull(update)) {
            update.setLimitNum(update.getLimitNum() + 1);
        }
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ClinicForRegist entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除号表安排
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 更新当前号
     *
     * @return
     */
    @Override
    @Transactional
    public Boolean updateCurrentNum(String clinicForRegistId, String orgId) {
        ClinicForRegistVo selectVo = baseMapper.selectVoById(clinicForRegistId);
        if (selectVo.getLimitNum() != 0 && selectVo.getLimitNum().equals(selectVo.getCurrentNum())) {
            throw new RuntimeException("此号今日已出完，不能再挂号，进行加号后再挂号，请刷新页面");
        }
        selectVo.setCurrentRegisNum(selectVo.getCurrentRegisNum() + 1);
        selectVo.setCurrentNum(selectVo.getCurrentRegisNum() + 1);
        return baseMapper.updateById(BeanUtil.toBean(selectVo, ClinicForRegist.class)) > 0;
    }
}
